package pay.serviceImpl;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import pay.common.ConstantFYJZH;
import pay.common.ConstantOrderStatus;
import pay.entity.OrderInfo;
import pay.entity.ProductInfo;
import pay.entity.SysUser;
import pay.entity.Trade;
import pay.portal.web.message.TransferOrderMsg;
import pay.service.*;
import pay.service.sys.ISysUser;
import pay.utils.BalanceUtils;
import pay.utils.DateUtil;
import pay.utils.FYApiUtil;
import pay.utils.JsonUtils;
import pay.utils.RedisCilent;
import pay.utils.SecurityUtils;
import pay.utils.StringHelper;
import pay.utils.XmlUtils;

@Service
public class TransferImpl implements ITransfer {
	
	protected Logger logger = LoggerFactory
			.getLogger(this.getClass().getName());
	/**
	 * 商户代码，从配置文件中读取
	 */
	@Value("${fy.mchntCd}")
	private String mchnt_cd;

	@Value("${fy.goldAccount.logsBaseUrl}")
	private String logsBaseUrl;
	
	@Value("${server.scheme}")
	private String serverScheme;
	
	/**
	 * 金账户baseURl，从配置文件中读取
	 */
	@Value("${fy.goldAccount.baseUrl}")
	private String jzhBaseUrl;
	
	@Value("${fy.goldAccount.pathBaseUrl}")
	private String pathBaseUrl;// 测试环境为/jzh 生产无。
	
	@Value("${server.url}")
	private String serverUrl;

	@Value("${producer.host}")
	private String host;

	@Value("${fy.transferLogFilePath}")
	private String logFilePath;

	@Autowired
	private ISysUser userService;

	@Autowired
	private ITrade tradeService;

	@Autowired
	private IOrderHelper orderHelperService;
	
	@Autowired
	private IOrderJpa orderJpaService;

	@Autowired
	private IProduct productJPA;

	@Override
	public Boolean transfer(String mchnt_txn_ssn){
		logger.info("标成立，进行划拨操作 mchnt_txn_ssn = {}", mchnt_txn_ssn);
		
		String transferMsgStr = this.getTransferRecordIntoRedis(mchnt_txn_ssn);
		if(StringHelper.isEmpty(transferMsgStr)){
			logger.info("标成立，进行划拨操作, 流水号在redis中不存在，将停止划拨 mchnt_txn_ssn ={}", mchnt_txn_ssn);
			return false;
		}
		
		TransferOrderMsg transferOrderMsg =  JsonUtils.toBean(transferMsgStr, TransferOrderMsg.class);
		
		Long orderId = transferOrderMsg.getOrderId();
		String  contractNo =  transferOrderMsg.getContractNo();
		String  outAccount =  transferOrderMsg.getOutAccount();
		String  inAccount =  transferOrderMsg.getInAccount();
		BigDecimal  amt = transferOrderMsg.getAmt();
		
		logger.info("标成立，进行划拨操作 transferOrderMsg = {}", transferOrderMsg.toString());
		
		if (orderId == null || StringHelper.isEmpty(contractNo)
				||StringHelper.isEmpty(outAccount)
				||StringHelper.isEmpty(inAccount)
				||amt == null) {
			logger.info("进行划拨，部分参数为空，划拨中断");
			return false;
		}
		
		logger.info(
				"即将进行划拨 out_num = {}, in_num ={}, contract_no ={}, amt = {}",
				outAccount, inAccount, contractNo, amt.toString());
		
		// 获取富友返回结果
		Boolean result = getTransferResult(orderId, mchnt_txn_ssn, outAccount,
				inAccount, contractNo, amt);
		
		logger.info("划拨的结果是： orderId={}, mchnt_txn_ssn ={}, result={}", orderId, mchnt_txn_ssn, result);
		
		//根据划拨结果更新相关信息
		updTransferResult(mchnt_txn_ssn, result);
		
		return result;
	}

	@Override
	public void addIntoTradeTable(Long orderId, Long userId, String login_id,
			BigDecimal amount, String mchnt_txn_ssn, String tradeDesc,
			String resp_code, String resp_desc) {
		Trade trade = new Trade();
		trade.setOrderId(orderId);
		trade.setUserId(userId);
		trade.setLogin_id(login_id);
		trade.setAmt(amount);
		trade.setCts(System.currentTimeMillis());
		trade.setMchnt_txn_ssn(mchnt_txn_ssn);
		trade.setFlowType(ConstantFYJZH.BALANCE_CUT);
		trade.setType(ConstantFYJZH.TRADE_TY_GM);
		trade.setTradeDesc(tradeDesc);
		trade.setResp_code(resp_code);
		trade.setResp_desc(resp_desc);

		//发送通知告知用户有错误信息
		if(resp_code.equals("0000") == false && tradeService.isExist(trade) == false){

			String prouctName = tradeService.getProductNameByTrade(trade);

			//短信内容
			String msg = "管理员您好！产品名称：" + prouctName + "，订单号：" + trade.getOrderId() + "，在进行起标划拨时发生错误，请注意并查找原因！";

			//邮件标题
			String emailMsgTitle = prouctName + "起标划拨错误通知邮件-重要!!！";

			//邮件内容
			String emailMsgContent = msg + "/n" + trade.toString();

			tradeService.sendErrorMsg(msg, emailMsgTitle, emailMsgContent);
		}

		tradeService.save(trade);
		
	}

	@Override
	public Boolean getTransferResult(Long orderId, String mchnt_txn_ssn,
			String out_cust_no, String in_cust_no, String contract_no,
			BigDecimal amt) {
		logger.info("进入8082 富友划拨接口");

		Boolean result = false;

		// 金额
		String rem = BalanceUtils.chgToFYVal(amt);

		logger.info(
				"进入富友划拨接口关键入参mchnt_txn_ssn={},out_cust_no={},in_cust_no={},contract_no={}, rem={}",
				mchnt_txn_ssn, out_cust_no, in_cust_no, contract_no,rem);
		
		//校验参数是否正常
		if (StringHelper.isEmpty(mchnt_txn_ssn)
				|| StringHelper.isEmpty(out_cust_no)
				|| StringHelper.isEmpty(in_cust_no)
				|| StringHelper.isEmpty(contract_no)
				|| StringHelper.isEmpty(rem)) {
			logger.info("入参有空参数");
			return false;
		}
		SysUser user = userService.getByPhoneNum( out_cust_no);
		
		if(user == null ){
			logger.error("订单划款参数检查，发现错误, 用户不存在，停止回款， orderId={}",orderId );
			return false;
		}

		// 调用富友接口，进行划拨
		String resultStr = sendPostToFY(mchnt_txn_ssn, contract_no,
				out_cust_no, in_cust_no, amt);
		
		logger.info("划拨结果是resultStr={} ", resultStr);
		String resultCode = XmlUtils.getVal(resultStr, "resp_code");
		
		logger.info("将划拨信息添加到trade表中 orderId={}", orderId);
		
		addIntoTradeTable(orderId, user.getId(), user.getName(), amt, mchnt_txn_ssn, "起标划拨", resultCode, ""); 
		
		if (StringHelper.isNotEmpty(resultCode) && resultCode.equals("0000")) {
			result = true;
		}
		
		//将划拨信息写入日志文件
		try {
			Long cts = System.currentTimeMillis();
			String logRecord = DateUtil.transferLongToDate(
					"yyyy-MM-dd HH:mm:ss", cts)
					+ "----富友划拨接口入参:  mchnt_txn_ssn = "
					+ mchnt_txn_ssn
					+ ",out_cust_no = "
					+ out_cust_no
					+ ",in_cust_no = "
					+ in_cust_no 
					+ ",rem = " + rem 
					+ ",resultCode="
					+ resultCode
					+ "\r\n";
			logger.info("富友划拨接口入参 = " + logRecord);
			writeFile(logRecord);

		} catch (Exception e) {
			logger.error("写绑卡文本文件失败！", e);
		}
		
		return result;
	}

	@Override
	public void writeFile(String record) {
		Long cts = System.currentTimeMillis();
		String pathName = "transferLogFilePath-"
				+ DateUtil.transferLongToDate("yyyyMM", cts) + ".txt";

		Path filePath = Paths.get(logFilePath + pathName);

		if (!Files.exists(filePath)) {
			try {
				StringBuilder fileStr = new StringBuilder();
				fileStr.append("0 | | 1\r\n").append(
						"序号|用户id|客户手机号|提现金额 |商户代码|请求流水号|响应码|创建时间\r\n");
				fileStr.append(record);

				Files.write(filePath, fileStr.toString().getBytes("UTF-8"));
			} catch (IOException e) {
				logger.error("首次写文件失败！", e);
				// e.printStackTrace();
			}
		} else {// 存在则追加
			try {
				Files.write(filePath, record.getBytes("UTF-8"),
						StandardOpenOption.APPEND);
			} catch (IOException e) {
				logger.error("追加写文件失败！", e);
				// e.printStackTrace();
			}

		}
		
	}

	@Override
	public String sendPostToFY(String mchnt_txn_ssn, String contract_no,
			String out_cust_no, String in_cust_no, BigDecimal amt) {
		
		// 金额
		String amtStr = BalanceUtils.chgToFYVal(amt);
		
		String rem = "";
		String pathUrl = pathBaseUrl + "/transferBu.action";
		URIBuilder builder = new URIBuilder().setScheme("https")
				.setHost(jzhBaseUrl).setPath(pathUrl);
		logger.info(builder.toString());
		Map<String, String> trimmedParams = new HashMap<>();

		String allUrl = amtStr + "|" + contract_no + "|" + in_cust_no + "|"
				+ mchnt_cd + "|" + mchnt_txn_ssn + "|" + out_cust_no + "|"
				+ rem;
		
		logger.info("金账户进行划拨  签名 = " + allUrl);
		
		SecurityUtils.initPrivateKey();
		SecurityUtils.initPublicKey();
		String signature = SecurityUtils.sign(allUrl);

		trimmedParams.put("mchnt_txn_ssn", mchnt_txn_ssn);
		trimmedParams.put("out_cust_no", out_cust_no);
		trimmedParams.put("in_cust_no", in_cust_no);
		trimmedParams.put("amt", amtStr);
		trimmedParams.put("contract_no", contract_no);
		trimmedParams.put("rem", rem);
		trimmedParams.put("signature", signature);
		trimmedParams.put("mchnt_cd", mchnt_cd);

		String openResult = FYApiUtil.doPost(builder, trimmedParams);
		return openResult;
	}

	@Override
	public void addTransferRecordIntoRedis(String mchnt_txn_ssn, String transferMsgStr ) {
		//首先将需要进行划拨的订单信息保存在redis中
		logger.info("划拨前，先将划拨信息保存在redis中， mchnt_txn_ssn={}，transferMsgStr={}", mchnt_txn_ssn,
				transferMsgStr);
		RedisCilent.setString(mchnt_txn_ssn, transferMsgStr, 172800);
		
	}

	@Override
	public String getTransferRecordIntoRedis(String mchnt_txn_ssn) {
		logger.info("从redis中 获取划拨信息 ， mchnt_txn_ssn={} ", mchnt_txn_ssn);
		
		String transferMsgStr = RedisCilent.getString(mchnt_txn_ssn);
		
		return transferMsgStr;
	}

	@Override
	public void delTransferRecordIntoRedis(String mchnt_txn_ssn) {
		logger.info("从redis中 删除划拨信息 ， mchnt_txn_ssn={} ", mchnt_txn_ssn);
		RedisCilent.delKey(mchnt_txn_ssn);
	}

	@Override
	public String getSSN(Long orderId) {
		
		String ctsLong = String.valueOf(System.currentTimeMillis());
		
		String cts = ctsLong.substring(ctsLong.length() - 4, ctsLong.length());
		
		//生成流水号
		String mchnt_txn_ssn = cts + orderId + ConstantFYJZH.MSSN_GM;
		
		return mchnt_txn_ssn;
	}

	@Override
	public Boolean updTransferResult(String mchnt_txn_ssn, Boolean result) {
		
		logger.info("标成立，根据划拨结果更新相关信息  updTransferResult  mchnt_txn_ssn = {}, result={}",
				mchnt_txn_ssn, result);
		
		if(!result){
			logger.info("标成立进行划拨操作, 划拨结果为未成功");
			return false;
		}
		String transferMsgStr = this.getTransferRecordIntoRedis(mchnt_txn_ssn);
		
		if(StringHelper.isEmpty(transferMsgStr)){
			logger.info("标成立进行划拨操作, 更新相关信息, 流水号在redis中不存在，将停止划拨  updTransferResult -- mchnt_txn_ssn ={}", mchnt_txn_ssn);
			return false;
		}
		
		TransferOrderMsg transferOrderMsg =  JsonUtils.toBean(transferMsgStr, TransferOrderMsg.class);
		
		Long orderId = transferOrderMsg.getOrderId();
		String  contractNo =  transferOrderMsg.getContractNo();
		String  outAccount =  transferOrderMsg.getOutAccount();
		String  inAccount =  transferOrderMsg.getInAccount();
		BigDecimal  amt = transferOrderMsg.getAmt();
		
		 
		logger.info(
				"标成立进行划拨操作,更新相关信息 updTransferResult --  , out_num = {}, in_num ={}, contract_no ={}, amt = {}",
				outAccount, inAccount, contractNo, amt.toString());

		OrderInfo orderInfoBf = orderJpaService.findById(orderId);
		logger.info("before update order status  orderId={}, payStatus={}, confirmStatus={}", orderInfoBf.getId(), orderInfoBf.getPayStatus(), orderInfoBf.getConfirmStatus());


		// 更新订单信息
		logger.info("划拨成功 step01，更改订单的确认状态 updTransferResult -- orderId={}", orderId);
		orderJpaService.updateOrderConfirmStatus(orderId, ConstantOrderStatus.CONFIRM_STATUS__TRUE, System.currentTimeMillis());


		OrderInfo orderInfoAfter = orderJpaService.findById(orderId);
		logger.info("after update order status  orderId={}, payStatus={}, confirmStatus={}", orderInfoAfter.getId(), orderInfoAfter.getPayStatus(), orderInfoAfter.getConfirmStatus());



		// 将回款信息写入trade 表中
		logger.info("划拨成功 step02,将订单记录从待划拨列表中删除 updTransferResult -- orderId={}", orderId);
		orderHelperService.delTransferOrderFromRedis(orderId, transferMsgStr);  	
		
		// 从reids 中删除相关信息
		logger.info("划拨成功 step03,将订单记录从redis中删除 updTransferResult -- mchnt_txn_ssn={}", mchnt_txn_ssn);
		delTransferRecordIntoRedis(mchnt_txn_ssn);
		
		return true;
	}
	
	
	 

}
